package app.keter.portal.security;

import app.keter.portal.security.core.AuthenticationFilter;
import com.keter.framework.core.config.AvoidScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.Arrays;

/**
 * SpringSecurity 核心功能入口
 */
@SuppressWarnings("SpringJavaAutowiringInspection")
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@AvoidScan //从单体测试排除
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Autowired private AuthenticationFilter authenticationFilter;
    @Autowired private UserDetailsService userDetailsService;
    @Autowired private PasswordEncoder passwordEncoder;

    public static final String LOGIN_PAGE = "/ajax/login"; //登录页

    /* 允许自由访问的URL */
    public static final String[] FREE_URL_PATTERNS = {
            LOGIN_PAGE,
            "/**/public/**",
            "/**/images/**",
            "/**/*.js",
            "/**/*.css",
            "/css/**",
            "/images/**",
            "/v2/api-docs",
            "/swagger-resources/**",
            "/swagger-ui.html"
            /*Probably not needed*/
            ,"/swagger.json"
            ,"/"
            ,"/ajax/login"
            ,"/authenticate"
            ,"/actuator/**"
            ,"/logout"
            ,"/css/**/*"  //适配有中横线和下级路径的url：/css/common/fonts/xxx-xxx.ttf
            ,"/console/**"
    };

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        //开放访问
        permitAll(httpSecurity);
        //平台管理员
        httpSecurity.authorizeRequests().antMatchers("/**/admin/**").hasRole("ADMIN");
        //设备管理员
        httpSecurity.authorizeRequests().antMatchers("/**/device/**").hasAnyRole("ADMIN","DEVICE_ADMIN");
        httpSecurity
                // 由于使用的是JWT，我们这里不需要csrf
                .csrf().disable()
                .cors() //配合CorsConfig完成跨域认证的支持
                .and()
                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                //注销由客户端实现：删除token即可
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl(LOGIN_PAGE)
        ;

        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);

        // 禁用缓存
        httpSecurity.headers().cacheControl();
    }

    private void permitAll(HttpSecurity httpSecurity){
        Arrays.stream(FREE_URL_PATTERNS).forEach(s -> {
            try {
                httpSecurity.authorizeRequests().antMatchers(s).permitAll();
            } catch (Exception e) {
                logger.info("", e);
            }
        });
    }
}
